package cn.com.doone.common.uc.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.codec.Base64;

import cn.com.doone.common.utils.ExtString;


public class PasswordUtils {
	
	/**
	 * MD5加密
	 * 
	 * @param password
	 * @return
	 */
	public static String md5Password(String password) {
		// qztelecom.oa.common.MD5 m = new qztelecom.oa.common.MD5();
		// String ret = m.getMD5ofStr(password);
		String ret = MD5.getMD5Str(password);
	    ret = ret.substring(8, 24);
		return ret;
	}
	
	public static String openLdapMD5(String password) throws NoSuchAlgorithmException {

		MessageDigest md = MessageDigest.getInstance("MD5"); 
		md.update(password.getBytes()); 
		byte[] bs = md.digest(); 
		byte[] base64MD5Password = Base64.encode(bs);
		
		return "{MD5}" + new String(base64MD5Password);
	}
	
	/**
	 * 验证密码是否是弱密码
	 * @param password
	 * @return
	 */
	public static String checkPassword(String password) {
		String pwd = password.trim();
        if (pwd.matches("^.*[\\s]+.*$")) {
            return "不能包含空格、制表符、换页符等空白字符";
        }

        int minLen = 8;
        int minGroup = 2;
        boolean isSameLetter = true;
        boolean isSameGroup = true;
        boolean isAdjacent = true;


        if (pwd.length() < minLen) {
            return "密码长度至少" + minLen + "位。";
        }

        // 检查弱密码组合；
        String[] letter = new String[] {"^.*[a-z]+.*$", "^.*[A-Z]+.*$", "^.*[0-9]+.*$", "^.*[\\p{Punct}]+.*$"};
        int cnt = 0;
        for (String s : letter) {
            if (pwd.matches(s)) {
                cnt++;
            }
        }
        if (cnt < minGroup) {
            return "必须包含数字、大写字母、小写字母、特殊字符等四种中的" + minGroup + "种字符。";
        }

        // 检查相同字符数，相同字符不能超过密码长度的1/2，最小为3位。
        if (isSameLetter) {
            int num = 3;
            if (pwd.length() > 9) {
                num = pwd.length() / 2 - 1;
            }
            String sameLetterRule = "^.*(.)\\1{" + num + ",}+.*$";
            if (pwd.matches(sameLetterRule)) {
                return "不能包含" + num + "位及以上相同字符的重复。";
            }
        }

        // 检查相同字符组合,默认为检查，检查规则是组合字符数为密码字符数的1/3，即8位密码检测3个字符组合。
        if (isSameGroup) {
            int num = 3;
            if (pwd.length() > 9 && pwd.length() % 3 == 0) {
                num = pwd.length() / 3;
            } else {
                num = pwd.length() / 3 + 1;
            }

            String sameGroupRule = "^.*(.{" + num + "})(.*)\\1+.*$";
            if (pwd.matches(sameGroupRule)) {
                return "不能包含" + num + "位及以上字符组合的重复。";
            }
        }

        // 按键盘输入相邻字符判断
        if (isAdjacent) {
            // @formatter:off
            String[][] keyboards = new String[][] {
                    {"2", "`1234567890-=-0987654321`"}, 
                    {"2", "qwertyuiop[]poiuytrewq"},
//                    {"2", "asdfghjkl;'lkjhgfdsa"}, 
//                    {"2", "zxcvbnm,./,mnbvcxz"}, 
//                    {"2", "~!@#$%^&*()_+_)(*&^%$#@!~"},
//                    {"2", "QWERTYUIOP{}|}{POIUYTREWQ"}, 
//                    {"2", "ASDFGHJKL:LKJHGFDSA"}, 
//                    {"2", "ZXCVBNM<>?><MNBVCXZ"},
//                    {"2", "951596369085258074147"},
//                    {"2", "1qazaq12wsxsw23edcde34rfvfr45tgbgt56yhnhy67ujmju78ik,ki89ol.lo90p;/;p0-['[-=]="},
//                    {"2", "!QAZAQ!@WSXSW@#EDCDE#$RFVFR$%TGBGT%^YHNHY^&UJMJU&*IK<KI*(OL>LO()P:?:P)_{_+}+|"},
                    {"3", "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"},
                    {"3", "ABCDEFGHIJKLMNOPQRSTUVWXYZYXWVUTSRQPONMLKJIHGFEDCBA"}, 
                    {"3", "0123456789876543210"}
            };
            // @formatter:on

            Set<String> msg = new HashSet<>();
            String pwd1 = pwd.replaceAll("[\\p{Punct}]", "");
            String pwd2 = pwd.replace("[0-9a-zA-Z]", "");
            for (String[] k : keyboards) {
                int c = ExtString.getInt(k[0]);
                for (int i = 0; i < pwd.length() - c; i++) {
                    String str = pwd.substring(i, i + c);
                    if (k[1].indexOf(str) >= 0) {
                        i++;
                        msg.add(str);
                    }
                }

                for (int i = 0; i < pwd1.length() - c; i++) {
                    String str = pwd1.substring(i, i + c);
                    if (k[1].indexOf(str) >= 0) {
                        i++;
                        msg.add(str);
                    }
                }

                for (int i = 0; i < pwd2.length() - c; i++) {
                    String str = pwd2.substring(i, i + c);
                    if (k[1].indexOf(str) >= 0) {
                        i++;
                        msg.add(str);
                    }
                }
            }

            // 连续字符数不能超过密码长度的2/3的个数，并且连接对数上于最小密码长度。
            int num = pwd.length() / 2 - 2;
            if (msg.size() > num && cnt > 2 && cnt < minLen) {
                // 如果各组字符不连续，作为合法密码。
                cnt = 0;
                String[] s = msg.toArray(new String[msg.size()]);
                for (int i = 0; i < s.length; i++) {
                    for (int j = i + 1; j < s.length; j++) {
                        char c00 = getNumber(s[i].charAt(0));
                        char c01 = getNumber(s[i].charAt(1));
                        char c10 = getNumber(s[j].charAt(0));
                        char c11 = getNumber(s[j].charAt(1));
                        if (Math.abs(c00 - c10) < 2 || Math.abs(c00 - c11) < 2 || Math.abs(c01 - c10) < 2
                                || Math.abs(c01 - c11) < 2) {
                            cnt++;
                        }
                    }
                }

                if (cnt >= num) {
                    return "不能包含" + (num + 1) + "组及以上正序及逆序连续字符(" + msg.toString() + ")";
                }
            }
        }
		return "";
	}
	
	private static char getNumber(final char c) {
        switch (c) {
        case '`':
        case '~':
            return '0';
        case '!':
            return '1';
        case '@':
            return '2';
        case '#':
            return '3';
        case '$':
            return '4';
        case '%':
            return '5';
        case '^':
            return '6';
        case '&':
            return '7';
        case '*':
            return '8';
        case '(':
            return '9';
        case ')':
            return '0';
        case '-':
        case '_':
            return '1';
        case '+':
        case '=':
            return '2';
        default:
            return c;
        }
    }
	
}
